/* $ZEL: sis1100_init_remote.c,v 1.10 2006/02/14 20:21:17 wuestner Exp $ */

/*
 * Copyright (c) 2001-2004
 * 	Matthias Drochner, Peter Wuestner.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "sis1100_sc.h"

static char* rnames[]= {
    "PCI",
    "VME",
    "CAMAC",
    "LVD",
};

void
sis1100_init_remote(struct sis1100_softc* sc)
{
    u_int32_t ident, error, balance, typ, hv, fk, fv;
    int res;

    SEM_LOCK(sc->sem_hw);

    /*sis1100writereg(sc, cr, cr_rem_reset);*/ /* reset remote */
    if (sis1100_flush_fifo(sc, "init_remote" , 0)) /* clear local fifo */
        return;
    sis1100writereg(sc, p_balance, 0);
    sis1100readreg(sc, prot_error);

    ident=plxreadlocal0(sc, 0x800);
    error=sis1100readreg(sc, prot_error);
    balance=sis1100readreg(sc, p_balance);
    SEM_UNLOCK(sc->sem_hw);

    if (error || balance) {
        pERROR(sc, "error reading remote ident");
        pERROR(sc, "error=0x%x balance=%d", error, balance);
        sis1100_flush_fifo(sc, "after reading ident" , 0); /* clear local fifo */
        /*sis1100_dump_glink_status(sc, "init remote");*/
        return;
    }

    typ=ident&0xff;
    hv=(ident>>8)&0xff;
    fk=(ident>>16)&0xff;
    fv=(ident>>24)&0xff;
    pINFO(sc, "remote ident: 0x%08x", ident);
    if ((typ>0) && (typ<=sizeof(rnames)/sizeof(char*)))
        pINFO(sc, "remote is %s", rnames[typ-1]);
    else
        pERROR(sc, "unknown remote type %d", ident&0xff);
    pINFO(sc, "remote HW_ver %d FW_code %d FW_ver %d", hv, fk, fv);
    sc->remote_ident=ident;

/* swapping is undefind here; it even would depend on arbitrary user settings */
    switch (typ) {
        case sis1100_hw_pci: /* PCI */
            res=sis1100rem_init(sc);
            sc->remote_endian=1; /* big endian; the remote side has to swap */
            break;
        case sis1100_hw_vme: /* VME */
            res=sis3100rem_init(sc);
            sc->remote_endian=1; /* big endian */
            break;
        case sis1100_hw_camac: /* CAMAC */
            res=sis5100rem_init(sc);
            sc->remote_endian=1; /* CAMAC is not yet known */
            break;
        case sis1100_hw_lvd: /* (ACAM TDC-F1 / Vertex) */
            res=zellvd_rem_init(sc);
            sc->remote_endian=0; /* Willi always uses little endian */
            break;
        default:
            pINFO(sc, "remote device type not (yet) supported.");
            sc->remote_endian=1; /* just a default */
            res=-1;
            break;
    }
    if (res) return;
    sis1100_update_swapping(sc, "init_remote");

    sc->old_remote_hw=sc->remote_hw;
    sc->remote_hw=typ;
}
